package auto

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"reflect"
	"regexp"
	"server/amtf"
	"server/global"
	"server/model/common/response"
	"text/template"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/pkg/errors"
	"gorm.io/datatypes"
)

func A查插件api(c *gin.Context) {
	插组件集 := A成插件给前端()

	// 检查是否可以正常编码json👇
	_, err := json.Marshal(插组件集)
	if err != nil {
		fmt.Println("插组件集 marshaling JSON 出错:", err)
		// c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to marshal JSON"})
		response.FailWithMessage(err.Error(), c)
		return
	}
	response.OkWithData(插组件集, c)
}

func A成插件给前端() map[string]any {
	插件 := A取插件()
	// 直接把全局 amtf.A插件集 给前端的话 json.Marshal 可能会因为 包含 函数字段而 转换报错
	// 这里只给字符串部分
	插组件集 := make(map[string]any)
	插组件集[插件.Name] = 插件
	for _, 组件 := range 插件.A组件s {
		组件id := 插件.Name + "." + 组件.Name
		插组件集[组件id] = 组件
		// 把model默认值给前端
		组件.Amodel = amtf.A组件集[组件id].Amodel
	}
	return 插组件集
}

func A取插件() *amtf.S插件 {
	插件 := &amtf.S插件{}
	jsonDataBytes := A取json("老鱼商店.json")
	json.Unmarshal(jsonDataBytes, 插件)
	return 插件
}

func A成插件文件json方式() {
	插件 := A取插件()
	amtf.A予插件_基础部分(插件)
	A成插件文件(插件)
	for _, 组件 := range 插件.A组件s {
		A成组件文件(插件, 组件)
	}
}

func A成插件文件(插件 *amtf.S插件) {
	targetDir := filepath.Join("aa", 插件.A英文名)
	A成模板文件(targetDir, "插件.go.tpl", 插件.Name, 插件)
}

func A成组件文件(插件 *amtf.S插件, 组件 *amtf.S组件) {
	组件.A插件名 = 插件.Name
	targetDir := filepath.Join("aa", 插件.A英文名, 组件.A英文名)
	A成模板文件(targetDir, "组件.go.tpl", 组件.Name, 组件)
	A成模板文件(targetDir, "model.go.tpl", 组件.Name+"model", 组件)
}

func 含json否(str string) bool {
	re := regexp.MustCompile(`arr|图片|富文本`)
	return re.MatchString(str)
}

func A成模板文件(targetDir string, 模板名 string, 文件名 string, 插件或组件 any) {
	fmt.Printf("插件或组件信息: %+v\n", 插件或组件)
	A字段组 := amtf.A取字段值(插件或组件, "A字段组")
	fmt.Printf("A字段组 👉 %+v\n", A字段组)
	os.MkdirAll(targetDir, 0755)
	tplPath := filepath.Join("amtf", "auto", "template", 模板名)

	tplContent, _ := os.ReadFile(tplPath)
	funcMap := template.FuncMap{
		"解json": 解json,
	}

	// tpl, err := template.New("example").Funcs(funcMap).Parse(tplContent)
	tpl, _ := template.New("插件或组件").Option("missingkey=zero").Funcs(funcMap).Parse(string(tplContent))
	outputFilePath := filepath.Join(targetDir, fmt.Sprintf("%s.go", 文件名))
	if _, err := os.Stat(outputFilePath); err == nil {
		// 获取当前时间毫秒数
		// now := time.Now().UnixNano() / 1e6
		now := time.Now().Format("2006-01-02 15-04.000")
		backupDir := filepath.Join(fmt.Sprintf("删除保留/%s", now), "aa")
		os.MkdirAll(backupDir, 0755)

		relPath, _ := filepath.Rel("aa", outputFilePath)
		backupFilePath := filepath.Join(backupDir, relPath)
		// 创建备份文件所在目录
		备份目录 := filepath.Dir(backupFilePath)
		os.MkdirAll(备份目录, 0755)
		// 转移文件
		os.Rename(outputFilePath, backupFilePath)
	}

	outputFile, _ := os.Create(outputFilePath)

	defer outputFile.Close()
	err := tpl.Execute(outputFile, 插件或组件)
	if err != nil {
		fmt.Printf("err 👉 %+v\n", err)
	}
}

// 将 datatypes.JSON 转换为 Go 语言中 datatypes.JSON 字面量格式的字符串
func 解json(data datatypes.JSON) map[string]any {
	var result map[string]any
	err := json.Unmarshal([]byte(data), &result)
	if err != nil {
		return nil
	}
	return result
}

// func A成组件(json文件 string, 插件 *amtf.S插件) (组件 *amtf.S组件) {
// 	jsonDataBytes := A取json(json文件)
// 	组件 = &amtf.S组件{}
// 	err := json.Unmarshal(jsonDataBytes, 组件)
// 	if err != nil {
// 		_ = fmt.Errorf("解析 JSON 文件失败: %w", err)
// 	}
// 	model := A成model(组件, 插件)
// 	组件.Amodel = model
// 	return
// }

func A取json(relativePath string) (jsonDataBytes []byte) {
	jsonFilePath := filepath.Join("amtf/auto/json", relativePath)
	jsonFile, err := os.Open(jsonFilePath)
	// fmt.Printf("jsonFilePath 👉 %+v\n", jsonFilePath)
	amtf.Printf("jsonFilePath 👉 %+v", jsonFilePath)
	fmt.Printf("err 👉 %+v\n", err)
	if err != nil {
		// return fmt.Errorf("打开 JSON 文件失败: %w", err)
		errors.Wrapf(err, "[jsonFilePath:%s] 出错!", jsonFilePath)
	}
	defer jsonFile.Close()

	// 读取文件内容
	jsonDataBytes, err = io.ReadAll(jsonFile)
	if err != nil {
		_ = fmt.Errorf("读取 JSON 文件内容失败: %w", err)
	}
	return
}

// 用反射动态生成的model不符合要求？字段名称显示为 internal/abi.Name {Bytes: *3} 不符合gorm首字母大写的要求？
func A成model_反射方式(组件 *amtf.S组件, 插件 *amtf.S插件) any {
	字段s := 组件.A字段组
	fields := make([]reflect.StructField, 0, len(字段s))

	for _, 字段 := range 字段s {
		var 字段类型 reflect.Type
		switch 字段.A类型 {
		case "string":
			字段类型 = reflect.TypeOf("")
		case "int":
			字段类型 = reflect.TypeOf(0)
		case "float64":
			字段类型 = reflect.TypeOf(0.0)
		// 可以根据需要添加更多类型
		default:
			fmt.Printf("不支持的类型: %s\n", 字段.A类型)
			continue
		}

		field := reflect.StructField{
			Name:    "A" + 字段.Name,
			Type:    字段类型,
			Tag:     reflect.StructTag(fmt.Sprintf(`json:"%s" gorm:"column:%s;comment:;"`, 字段.Name, 字段.Name)),
			PkgPath: "",
		}
		fields = append(fields, field)
	}

	structType := reflect.StructOf(fields)
	instance := reflect.New(structType).Elem()
	kk := instance.Interface()
	return kk
}

func A成modeldd(组件 *amtf.S组件, 插件 *amtf.S插件) any {
	字段s := 组件.A字段组
	fields := make([]reflect.StructField, 0, len(字段s))

	基础modelType := reflect.TypeOf(amtf.S基础model{})
	基础modelField := reflect.StructField{
		Name: "S基础model",
		Type: 基础modelType,
		Tag:  reflect.StructTag(""),
	}
	fields = append(fields, 基础modelField)

	for _, 字段 := range 字段s {
		var 字段类型 reflect.Type
		switch 字段.A类型 {
		case "string":
			字段类型 = reflect.TypeOf("")
		case "int":
			字段类型 = reflect.TypeOf(0)
		case "float64":
			字段类型 = reflect.TypeOf(0.0)
		// 可以根据需要添加更多类型
		default:
			fmt.Printf("不支持的类型: %s\n", 字段.A类型)
			continue
		}

		field := reflect.StructField{
			Name: "A" + 字段.Name,
			Type: 字段类型,
			Tag:  reflect.StructTag(fmt.Sprintf(`json:"%s" gorm:"column:%s;comment:;"`, 字段.Name, 字段.Name)),
		}
		fields = append(fields, field)
	}

	// 将 TableName 方法作为一个 StructField 添加
	methodField := reflect.StructField{
		Name:    "TableName",
		Type:    tableNameMethodType,
		PkgPath: "", // 导出方法
	}
	fields = append(fields, methodField)

	// 生成包含 TableName 方法的结构体类型
	structType := reflect.StructOf(fields)

	// 创建结构体实例
	instance := reflect.New(structType).Elem()

	// 设置 TableName 方法的值
	methodValue := createTableNameMethod(插件, 组件)
	instance.FieldByName("TableName").Set(methodValue)
	kk := instance.Interface()
	return kk

}

// 定义 TableName 方法类型
var tableNameMethodType = reflect.TypeOf(func() string { return "" })

// 创建 TableName 方法函数
func createTableNameMethod(插件 *amtf.S插件, component *amtf.S组件) reflect.Value {
	return reflect.MakeFunc(tableNameMethodType, func(args []reflect.Value) []reflect.Value {
		return []reflect.Value{reflect.ValueOf(fmt.Sprintf("%s_%s", 插件.Name, component.Name))}
	})
}

// 判断字符串是否是合法的包名
func 包名可否(name string) bool {
	match, _ := regexp.MatchString("^[a-zA-Z_]+[a-zA-Z0-9_]*$", name)
	return match
}

func Auto(relativePath string) error {
	// 获取当前执行文件的目录
	// currentDir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	// templateDir := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, "resource", entity.Template)

	// if err != nil {
	// 	// return fmt.Errorf("获取当前目录失败: %w", err)
	// 	return errors.Wrapf(err, "[filepath:%s] 出错!", relativePath)
	// }

	// 拼接完整的文件路径
	jsonFilePath := filepath.Join(global.GVA_CONFIG.AutoCode.Root, "server/插件", relativePath)

	// 打开 JSON 文件
	jsonFile, err := os.Open(jsonFilePath)
	// fmt.Printf("jsonFilePath 👉 %+v\n", jsonFilePath)
	amtf.Printf("jsonFilePath 👉 %+v", jsonFilePath)
	fmt.Printf("err 👉 %+v\n", err)
	if err != nil {
		// return fmt.Errorf("打开 JSON 文件失败: %w", err)
		return errors.Wrapf(err, "[jsonFilePath:%s] 出错!", jsonFilePath)
	}
	defer jsonFile.Close()

	// 读取文件内容
	jsonDataBytes, err := io.ReadAll(jsonFile)
	if err != nil {
		return fmt.Errorf("读取 JSON 文件内容失败: %w", err)
	}

	var 组件 amtf.S组件
	err = json.Unmarshal(jsonDataBytes, &组件)
	if err != nil {
		return fmt.Errorf("解析 JSON 文件失败: %w", err)
	}

	folderName := filepath.Dir(relativePath)
	var packageName string
	if 包名可否(folderName) {
		packageName = folderName
	} else {
		packageName = 组件.A英文名
	}
	fmt.Printf("可以继续 packageName 👉 %+v\n", packageName)
	// generateStruct(组件, packageName)
	return nil
}
